//=============================================================================
///	Stream
//=============================================================================

#include "stream.h"
#include <assert.h>

//=============================================================================
// File stream

static void filestream_close(StreamBase* strm) {
	FileStream* p = (FileStream*)strm;
//	fclose(p->fp);
	p->fp = NULL;
}

static int filestream_getc(StreamBase* strm) {
	FileStream* p = (FileStream*)strm;
	return fgetc(p->fp);
}

static void filestream_ungetc(StreamBase* strm, int c) {
	FileStream* p = (FileStream*)strm;
	ungetc(c, p->fp);
}

static void filestream_puts(StreamBase* strm, const char* str, int len) {
	FileStream* p = (FileStream*)strm;
	if (len == 0) {
		fputs(str, p->fp);
	} else {
		fprintf(p->fp, "%.*s", len, str);
	}
}

static void filestream_flush(StreamBase* strm) {
	FileStream* p = (FileStream*)strm;
	fflush(p->fp);
}

static const StreamVTbl FileStreamVTbl= {
	filestream_close,
	filestream_getc,
	filestream_ungetc,
	filestream_puts,
	filestream_flush,
};

StreamBase* make_file_stream(FileStream* p, FILE* fp) {
	p->parent.vtbl = &FileStreamVTbl;
	p->fp = fp;
	return &p->parent;
}

//=============================================================================
// String stream

static void stringstream_close(StreamBase* strm) {
	StringStream* p = (StringStream*)strm;
}

static int stringstream_getc(StreamBase* strm) {
	StringStream* p = (StringStream*)strm;
	if (p->p < p->str + p->len) {
		return *p->p++;
	} else {
		return EOF;
	}
}

static void stringstream_ungetc(StreamBase* strm, int c) {
	StringStream* p = (StringStream*)strm;
	if (p->p > p->str) {
		--p->p;
	}
}

static void stringstream_puts(StreamBase* strm, const char* str, int len) {
	StringStream* p = (StringStream*)strm;
	assert(!"not implemented");
}

static void stringstream_flush(StreamBase* strm) {
	StringStream* p = (StringStream*)strm;
	// nothing
}

static const StreamVTbl StringStreamVTbl= {
	stringstream_close,
	stringstream_getc,
	stringstream_ungetc,
	stringstream_puts,
	stringstream_flush,
};

StreamBase* make_string_stream(StringStream* p, const char* str, size_t len) {
	p->parent.vtbl = &StringStreamVTbl;
	p->str = str;
	p->len = len;
	p->p = str;
	return &p->parent;
}
